#!/usr/bin/env python
# -*- coding:utf8 -*-
# uncompyle6 version 2.15.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 2.7.10 (default, Jul  1 2017, 13:36:56) 
# [GCC 4.4.6 20110731 (Red Hat 4.4.6-4)]
# Embedded file name: ./paas/app/views.py
# Compiled at: 2017-11-16 15:44:28
"""
Tencent is pleased to support the open source community by making 蓝鲸智云(BlueKing) available.
Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
"""
from django.conf import settings
from django.http import HttpResponseRedirect
from django.db import transaction
from django.db.models import Q
from django.contrib.auth import get_user_model
from common.decorators import is_app_developer
from common.mymako import render_mako_context, render_json, render_mako_tostring_context
from common.log import logger
from app.models import App, SecureInfo, AppTags
from app.utils import validate_app_code, validate_app_name, validate_vcs_url, validate_app_tags, get_all_users
from app.constants import DB_TYPE_CHOICES, VCS_TYPE_CHOICES, AppOpenEnum, AppStateEnum
from release.utils import update_app_state
from engine.models import BkServer

def check_app_code(request):
    """
    检查新的app_code是否已经存在
    """
    app_code = request.GET.get('app_code', '')
    is_valid, message = validate_app_code(app_code)
    return render_json({'result': is_valid,'message': message})


def check_app_name(request):
    """
    检查app名称
    """
    name = request.GET.get('name', '')
    old_name = request.GET.get('old_name', '')
    is_valid, message = validate_app_name(name, old_name)
    return render_json({'result': is_valid,'message': message})


def create_app(request):
    """
    创建应用.
    
    Get请求到创建页面，post页面则保存应用信息后到基本信息页面
    """
    if request.method == 'GET':
        user_model = get_user_model()
        bk_token = request.COOKIES.get(settings.BK_COOKIE_NAME, None)
        res, users = get_all_users(bk_token)
        if not res:
            users = user_model.objects.all().values('username')
        error = request.GET.get('error', '')
        context = dict(error=error, db_type_choices=DB_TYPE_CHOICES, vcs_type_choices=VCS_TYPE_CHOICES, users=users)
        return render_mako_context(request, 'app/create.html', context)
    return _save_app(request)
    return


def _save_app(request):
    """
    新建应用
    """
    creater = request.user.username
    code = request.POST.get('code', '').replace('&nbsp;', ' ').strip()
    name = request.POST.get('name', '').replace('&nbsp;', ' ').strip()
    introduction = request.POST.get('introduction', '').replace('&nbsp;', ' ').strip()
    app_tags = request.POST.get('app_tags')
    language = request.POST.get('language', 'python')
    deploy_token = request.POST.get('deploy_token', '').replace('&nbsp;', ' ').strip()
    vcs_type = request.POST.get('vcs_type')
    vcs_url = request.POST.get('vcs_url', '').replace('&nbsp;', ' ').strip()
    vcs_username = request.POST.get('vcs_username', '').replace('&nbsp;', ' ').strip()
    vcs_password = request.POST.get('vcs_password', '').replace('&nbsp;', ' ').strip()
    developer = request.POST.get('developer', creater)
    if developer:
        developer_list = developer.split(';') if 1 else []
        error_url = u'%sapp/create/?error={error}' % settings.SITE_URL
        is_code_valid, code_msg = validate_app_code(code)
        if not is_code_valid:
            return HttpResponseRedirect(error_url.format(error=code_msg))
        is_name_valud, name_msg = validate_app_name(name, '')
        if not is_name_valud:
            return HttpResponseRedirect(error_url.format(error=name_msg))
        is_vcs_valid, vcs_msg = validate_vcs_url(vcs_type, vcs_url)
        return is_vcs_valid or HttpResponseRedirect(error_url.format(error=vcs_msg))
    is_tags_valid, tags_msg, app_tags = validate_app_tags(app_tags)
    from engine.api import register_app
    is_success, register_result = register_app(code, name, language)
    token = register_result.get('token', '') if register_result else ''
    if not is_success or not token:
        logger.error(u'应用[%s]注册失败, 失败信息:%s' % (code, register_result))
        error_msg = u'应用注册失败,可能原因:App Engine 未正常启动'
        return HttpResponseRedirect(error_url.format(error=error_msg))
    try:
        with transaction.atomic():
            app = App.objects.create(name=name, code=code, introduction=introduction, creater=creater, language=language, auth_token=token, deploy_token=deploy_token, tags=app_tags)
            if developer_list:
                user_model = get_user_model()
                for dev in developer_list:
                    try:
                        d_user, _c = user_model.objects.get_or_create(username=dev)
                        app.developer.add(d_user)
                    except Exception as e:
                        logger.exception(u'获取用户[username:%s]异常:%s' % (dev, e))

            SecureInfo.objects.create(app_code=code, vcs_type=vcs_type, vcs_url=vcs_url, vcs_username=vcs_username, vcs_password=vcs_password)
    except Exception as e:
        logger.exception(u'创建应用时，保存应用基本信息出错:%s' % e)
        return HttpResponseRedirect(error_url.format(error=u'保存应用基本信息出错'))

    return HttpResponseRedirect('%sapp/info/%s/' % (settings.SITE_URL, code))


@is_app_developer
def modify_app(request, app_code):
    """
    编辑应用基本信息
    """
    operate = request.POST.get('operate', '')
    if not operate:
        return render_json({'result': False,'msg': u'参数异常'})
    app = App.objects.get(code=app_code)
    if operate == 'base':
        name = request.POST.get('name', '').replace('&nbsp;', ' ').strip()
        old_name = app.name
        is_valid, message = validate_app_name(name, old_name)
        return is_valid or render_json({'result': False,'msg': message})
    developer = request.POST.get('developer', '')
    if developer:
        developer_list = developer.split(';') if 1 else []
        if not developer_list:
            return render_json({'result': False,'msg': u'负责人不能为空'})
        app_tags = request.POST.get('app_tags', '')
        is_tags_valid, tags_msg, app_tags = validate_app_tags(app_tags)
        try:
            with transaction.atomic():
                app.name = name
                app.tags = app_tags
                app.save()
                if developer_list:
                    app.developer.clear()
                    user_model = get_user_model()
                    for dev in developer_list:
                        d_user, _c = user_model.objects.get_or_create(username=dev)
                        app.developer.add(d_user)

        except Exception as e:
            logger.exception(u'保存用户基本信息异常:%s' % e)
            return render_json({'result': False,'msg': u'编辑失败'})

    else:
        if operate == 'introduction':
            introduction = request.POST.get('introduction', '').replace('&nbsp;', ' ').strip()
            if not introduction:
                return render_json({'result': False,'msg': u'应用简介不能为空'})
            app.introduction = introduction
            app.save()
        else:
            if operate == 'vcs':
                vcs_type = request.POST.get('vcs_type')
                vcs_url = request.POST.get('vcs_url', '').replace('&nbsp;', ' ').strip()
                vcs_username = request.POST.get('vcs_username', '').replace('&nbsp;', ' ').strip()
                vcs_password = request.POST.get('vcs_password', '').replace('&nbsp;', ' ').strip()
                if not all([vcs_url, vcs_username, vcs_password]):
                    return render_json({'result': False,'msg': u'代码URL,用户名,密码不能为空'})
                is_vcs_valid, vcs_msg = validate_vcs_url(vcs_type, vcs_url)
                if not is_vcs_valid:
                    return render_json({'result': False,'msg': vcs_msg})
                SecureInfo.objects.filter(app_code=app_code).update(vcs_url=vcs_url, vcs_username=vcs_username, vcs_password=vcs_password)
            else:
                if operate == 'db':
                    db_host = request.POST.get('db_host', '')
                    db_port = request.POST.get('db_port', '')
                    db_username = request.POST.get('db_username', '')
                    db_password = request.POST.get('db_password', '')
                    if not all([db_host, db_username]):
                        return render_json({'result': False,'msg': u'数据库信息不能为空'})
                    if not db_port.isdigit():
                        return render_json({'result': False,'msg': u'数据库端口必须为整数'})
                    SecureInfo.objects.filter(app_code=app_code).update(db_host=db_host, db_port=db_port, db_username=db_username, db_password=db_password)
    return render_json({'result': True,'msg': u'编辑成功'})


def modify_app_logo(request, app_code):
    """
    修改应用图标
    """
    app = App.objects.get(code=app_code)
    logo = request.FILES.get('logo_m', '')
    if not logo:
        error = '更换logo失败, logo必须为png格式'
        return HttpResponseRedirect('%sapp/list/?error=%s' % (settings.SITE_URL, error))
    try:
        log_type = logo.content_type
        if log_type == 'image/png':
            app.logo = logo
            app.save()
    except:
        logger.exception(u'应用logo[%s]更换失败' % app_code)

    return HttpResponseRedirect('%sapp/list/' % settings.SITE_URL)


def app_list(request):
    """
    应用列表页
    """
    return render_mako_context(request, 'app/list.html', {})


def query_app_list(request):
    """
    查询获得app列表
    """
    username = request.user.username
    keyword = request.GET.get('keyword').replace('&nbsp;', '').strip()
    try:
        hide_outline = int(request.GET.get('hide_outline', '0'))
        page = int(request.GET.get('page', 1))
        page_size = int(request.GET.get('page_size', 8))
    except Exception as e:
        logger.exception(u'应用列表页面参数异常:%s' % e)
        return render_json({'data': u'请求参数异常',
           'total_num': 0,
           'extend_fun': ''
           })

    start = (page - 1) * page_size
    end = page * page_size
    app_all_list = App.objects.filter(is_saas=False)
    if request.user.is_superuser:
        app_all_list = app_all_list.order_by('-created_date')
    else:
        app_all_list = app_all_list.filter(Q(developer__username=username) | Q(creater=username)).order_by('-created_date').distinct()
    has_app = app_all_list.count() > 0
    if keyword:
        app_all_list = app_all_list.filter(Q(name__icontains=keyword) | Q(code__icontains=keyword) | Q(creater__icontains=keyword))
    if hide_outline == 0:
        app_all_list = app_all_list.exclude(state=0)
    total = app_all_list.count()
    app_list = app_all_list[start:end]
    refresh_app_list = []
    app_refresh_states = [
     AppStateEnum.IN_TEST, AppStateEnum.IN_ONLINE, AppStateEnum.IN_OUTLINE]
    for _app in app_list:
        if _app.state in app_refresh_states:
            _app_code = _app.code
            try:
                update_app_state(_app_code)
                _app = App.objects.get(code=_app_code)
            except:
                logger.exception(u'更新应用[%s]状态失败' % _app_code)

        refresh_app_list.append(_app)

    result = {'total': total,
       'app_list': refresh_app_list,
       'has_app': has_app
       }
    template_name = 'app/list_table.part' if has_app else 'app/list_tip.part'
    html_data = render_mako_tostring_context(request, template_name, result)
    return render_json({'data': html_data,
       'total_num': total,
       'extend_fun': ''
       })


@is_app_developer
def info(request, app_code):
    """
    应用基本信息
    """
    app_info = {}
    error = ''
    try:
        app = App.objects.get(code=app_code)
    except:
        error = u'应用[ID:%s]不存在' % app_code
        return render_mako_context(request, 'app/info_error.html', {'error': error,'app_code': app_code})

    try:
        app_secure_info = SecureInfo.objects.get(app_code=app_code)
    except:
        logger.info(u'应用[ID:%s]的源码信息不存在' % app_code)
        app_secure_info = None

    user_model = get_user_model()
    bk_token = request.COOKIES.get(settings.BK_COOKIE_NAME, None)
    res, users = get_all_users(bk_token)
    if not res:
        users = user_model.objects.all().values('username')
    alltags = AppTags.objects.all()
    tags = [ [tag.code, tag.name] for tag in alltags if tag ]
    developers_value_name_list = app.developer.all().values_list('username', flat=True)
    developers_value_name = (';').join(developers_value_name_list)
    vcs_type = app_secure_info.vcs_type if app_secure_info else ''
    app_info = {'code': app.code,
       'auth_token': app.auth_token,
       'creater': app.creater or '',
       'name': app.name or '',
       'state': app.state,
       'tags': app.tags.name if app.tags else '',
       'tags_code': app.tags.code if app.tags else '',
       'app_test_url': app.app_test_url,
       'app_pro_url': app.app_pro_url,
       'first_test_time': app.first_test_time_display or '',
       'first_online_time': app.first_online_time_display or '',
       'introduction': app.introduction_display or '',
       'deploy_token': app.deploy_token or '',
       'vcs_type': vcs_type,
       'vcs_type_name': dict(VCS_TYPE_CHOICES).get(vcs_type, ''),
       'vcs_url': app_secure_info.vcs_url if app_secure_info else '',
       'vcs_username': app_secure_info.vcs_username if app_secure_info else '',
       'vcs_password': app_secure_info.vcs_password if app_secure_info else '',
       'developers_value_name': developers_value_name,
       'developers_value_name_list': developers_value_name_list or [],
       'users': users
       }
    if error or not app_info:
        return render_mako_context(request, 'app/info_error.html', {'error': error,'app_code': app_code})
    context = {'app_info': app_info,
       'app_code': app_code,
       'tags': tags
       }
    return render_mako_context(request, 'app/info.html', context)


def app_status(request, app_code):
    """
    应用状态
    
    res值:
    1    正式环境，测试环境都打开
    2    只有测试环境
    3    只有正式环境
    4    正式环境，测试环境都关闭
    """
    try:
        app = App.objects.get(code=app_code)
    except:
        logger.exception(u'app status 应用[id:%s]不存在' % app_code)
        context = {'result': 0,'app_test_url': '###','app_pro_url': '###','app_name': ''}
        return render_json(context)

    is_test = app.state not in [AppStateEnum.DEVELOPMENT] and app.is_already_test
    is_pro = app.state not in [AppStateEnum.OUTLINE, AppStateEnum.DEVELOPMENT] and app.is_already_online
    if is_pro and is_test:
        res = AppOpenEnum.OPEN_IN_ALL
    else:
        if is_pro:
            res = AppOpenEnum.OPEN_IN_PRO
        else:
            if is_test:
                res = AppOpenEnum.OPEN_IN_TEST
            else:
                res = AppOpenEnum.OPEN_NONE
    context = {'result': res,
       'app_test_url': app.app_test_url,
       'app_pro_url': app.app_pro_url,
       'app_name': app.name,
       'app_logo_ur': app.get_logo_url
       }
    return render_json(context)


def get_vcs_password(request, app_code):
    """
    获取代码仓库密码
    """
    try:
        app_secure_info = SecureInfo.objects.get(app_code=app_code)
    except:
        res = False
        msg = u'应用[ID:%s]的源码信息不存在' % app_code
    else:
        res = True
        msg = app_secure_info.vcs_password

    return render_json({'res': res,'msg': msg})


def error(request, error_id, app_code):
    """
    错误提示信息
    """
    template_name = 'error/app_error_dialog%s.html' % error_id
    return render_mako_context(request, template_name, {'app_code': app_code})


def get_apptags(request):
    """
    获取app 分类列表
    """
    alltags = AppTags.objects.all()
    tags_name = tags_code = []
    for tag in alltags:
        tags_name.append(tag.name)
        tags_code.append(tag.code)

    return render_json({'tags_name': tags_name,'tags_code': tags_code})


def show_apply_process(request):
    """
    激活码申请流程
    """
    app_code = request.GET.get('app_code', '')
    is_base_info = request.GET.get('is_base_info')
    active_servers = BkServer.objects.filter(is_active=True)
    active_server_ips = active_servers.values_list('ip_address', flat=True)
    active_server_ips = (';').join(set(active_server_ips))
    active_servers_count = active_servers.count()
    mac_list = active_servers.values_list('mac', flat=True)
    if len(mac_list) == active_servers_count:
        mac_info = (';').join(mac_list)
    else:
        mac_info = ''
    context = {'is_base_info': is_base_info,'app_code': app_code,
       'mac_info': mac_info,
       'active_server_ips': active_server_ips
       }
    return render_mako_context(request, 'app/show_apply_process.html', context)
